/*
 * Yabumi, a 2d scrolling shoot-em-up game.
 * Copyright (C) 2003 Gemma Teruaki <terugen@yabumi.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
 */

#include <stdlib.h>
#include "task/hitcircle.h"
#include "task/player.h"
#include "task/enemy.h"
#include "task/musashi.h"
#include "task/missile.h"
#include "task/flame.h"
#include "task/homing.h"
#include "task/item.h"
#include "task/smoke.h"
#include "task/explosion.h"
#include "task/homing_tail.h"
#include "task/radar.h"
#include "scene_task/game.h"
#include "scene_task/title.h"
#include "taskmanager.h"

_list_header task_list_header[2];
_list_header *active_task_list_header, *expired_task_list_header;

static void Task_Add_Ex(_task_item *src_task_item);
static void Swap_task_list_header(_list_header **argA, _list_header **argB);
static int compare_task_priority(const _task_item *t0, const _task_item *t1);

void Task_Init()
{
  active_task_list_header = &task_list_header[0];
  expired_task_list_header = &task_list_header[1];
  Create_list(active_task_list_header);
  Create_list(expired_task_list_header);
}

void Task_Free()
{
  _list_item *list_item;
  _task_item *task_item;
  list_item = active_task_list_header->next->next;
  while (list_item != active_task_list_header->prev) {
    task_item = &list_item->data.task_item;
    task_item->option.count = KILL_COUNT;
    list_item = list_item->next;
  };
  list_item = expired_task_list_header->next->next;
  while (list_item != expired_task_list_header->prev) {
    task_item = &list_item->data.task_item;
    task_item->option.count = KILL_COUNT;
    list_item = list_item->next;
  };
  /* neglected free dummy */
}

void Task_Add(_funcpointer fp, void *socket0, void *socket1, int count)
{
  if (count == KILL_COUNT) {
    printf("Invalid Task added!\n");
    return;
  };
  _list_item *list_item;
  list_item = (_list_item *)pmalloc(sizeof(_list_item));
  Add_item_last(expired_task_list_header, list_item);
  _task_item *task_item = &list_item->data.task_item;

  task_item->root = list_item;
  task_item->fp = fp;
  task_item->option.socket[0] = socket0;
  task_item->option.socket[1] = socket1;
  task_item->option.count = count;
}

char* funcpointer_translater(_funcpointer fp)
{
  if (fp == Hitcircle_Add) return "Hitcircle_Add";
  if (fp == Hitcircle_Move) return "Hitcircle_Move";
  if (fp == Hitcircle_Kill) return "Hitcircle_Kill";
  if (fp == Player_Add) return "Player_Add";
  if (fp == Player_Move) return "Player_Move";
  if (fp == Player_Draw) return "Player_Draw";
  if (fp == Player_Fire_Missile) return "Player_Fire_Missile";
  if (fp == Player_Fire_Flame) return "Player_Fire_Flame";
  if (fp == Player_Rotate_Left) return "Player_Rotate_Left";
  if (fp == Player_Rotate_Right) return "Player_Rotate_Right";
  if (fp == Player_Thrust) return "Player_Thrust";
  if (fp == Player_was_Hit) return "Player_was_Hit";
  if (fp == Player_was_Hit_by_Missile) return "Player_was_Hit_by_Missile";
  if (fp == Player_was_Hit_by_Flame) return "Player_was_Hit_by_Flame";
  if (fp == Player_was_Hit_by_Item_Missile) return "Player_was_Hit_by_Item_Missile";
  if (fp == Player_was_Hit_by_Item_Flame) return "Player_was_Hit_by_Item_Flame";
  if (fp == Player_Lockon_Hitcircle) return "Player_Lockon_Hitcircle";
  if (fp == Player_Fire_Homing_Wait) return "Player_Fire_Homing_Wait";
  if (fp == Player_Lockon_Hitcircle_Wait) return "Player_Lockon_Hitcircle_Wait";
  if (fp == Player_Kill) return "Player_Kill";
  if (fp == Enemy_Add) return "Enemy_Add";
  if (fp == Enemy_Move) return "Enemy_Move";
  if (fp == Enemy_Draw) return "Enemy_Draw";
  if (fp == Enemy_Fire) return "Enemy_Fire";
  if (fp == Enemy_Fire_Missile) return "Enemy_Fire_Missile";
  if (fp == Enemy_Fire_Flame) return "Enemy_Fire_Flame";
  if (fp == Enemy_Rotate_Left) return "Enemy_Rotate_Left";
  if (fp == Enemy_Rotate_Right) return "Enemy_Rotate_Right";
  if (fp == Enemy_Thrust) return "Enemy_Thrust";
  if (fp == Enemy_was_Hit) return "Enemy_was_Hit";
  if (fp == Enemy_was_Hit_by_Missile) return "Enemy_was_Hit_by_Missile";
  if (fp == Enemy_was_Hit_by_Flame) return "Enemy_was_Hit_by_Flame";
  if (fp == Enemy_was_Hit_by_Homing) return "Enemy_was_Hit_by_Homing";
  if (fp == Enemy_was_Hit_by_Item_Missile) return "Enemy_was_Hit_by_Item_Missile";
  if (fp == Enemy_was_Hit_by_Item_Flame) return "Enemy_was_Hit_by_Item_Flame";
  if (fp == Enemy_Kill) return "Enemy_Kill";
  if (fp == Musashi_Add) return "Musashi_Add";
  if (fp == Musashi_Move) return "Musashi_Move";
  if (fp == Musashi_Draw) return "Musashi_Draw";
  if (fp == Musashi_Fire) return "Musashi_Fire";
  if (fp == Musashi_was_Hit) return "Musashi_was_Hit";
  if (fp == Musashi_was_Hit_by_Missile) return "Musashi_was_Hit_by_Missile";
  if (fp == Musashi_was_Hit_by_Flame) return "Musashi_was_Hit_by_Flame";
  if (fp == Musashi_was_Hit_by_Homing) return "Musashi_was_Hit_by_Homing";
  if (fp == Musashi_Kill) return "Musashi_Kill";
  if (fp == Missile_Add) return "Missile_Add";
  if (fp == Missile_Move) return "Missile_Move";
  if (fp == Missile_Draw) return "Missile_Draw";
  if (fp == Missile_Kill) return "Missile_Kill";
  if (fp == Flame_Add) return "Flame_Add";
  if (fp == Flame_Move) return "Flame_Move";
  if (fp == Flame_Draw) return "Flame_Draw";
  if (fp == Flame_Kill) return "Flame_Kill";
  if (fp == Homing_Add) return "Homing_Add";
  if (fp == Homing_Move) return "Homing_Move";
  if (fp == Homing_Kill) return "Homing_Kill";
  if (fp == Item_Add) return "Item_Add";
  if (fp == Item_Move) return "Item_Move";
  if (fp == Item_Draw) return "Item_Draw";
  if (fp == Item_Kill) return "Item_Kill";
  if (fp == Explosion_Draw) return "Explosion_Draw";
  if (fp == Explosion_Kill) return "Explosion_Kill";
  if (fp == Smoke_Draw) return "Smoke_Draw";
  if (fp == Smoke_Kill) return "Smoke_Kill";
  if (fp == Homing_Tail_Draw) return "Homing_Tail_Draw";
  if (fp == Homing_Tail_Kill) return "Homing_Tail_Kill";
  if (fp == Radar_Draw) return "Radar_Draw";
  return 0;
}

static int compare_task_priority(const _task_item *t0, const _task_item *t1)
{
  _funcpointer tt[2];
  tt[0] = t0->fp;
  tt[1] = t1->fp;
  int a[2] = {5,5};
  int i;
  for (i = 0; i < 2; i++) {
    /* if (tt[i] == Player_Add) a[i] = 5; */
    /* if (tt[i] == Player_Move) a[i] = 5; */
    /*                   ...               */
    /* i.e  5 is a default priority.       */
    if (tt[i] == Player_Move) a[i] = 3;
    if (tt[i] == Enemy_Move) a[i] = 3;
    if (tt[i] == Missile_Draw) a[i] = 4;
    if (tt[i] == Flame_Draw) a[i] = 4;
    if (tt[i] == Scene_Game) a[i] = 2;
    if (tt[i] == Scene_Title) a[i] = 2;
  };
  if (a[0] < a[1]) return 1;
  if (a[0] == a[1]) return 0;
  if (a[0] > a[1]) return -1;
  return 0;
}

void Task_Schedular()
{
/*   qsort(active_tasklist->item,\ */
/* 	active_tasklist->size,\ */
/* 	sizeof(active_tasklist->item[0]),\ */
/* 	(int(*)(const void*, const void*))compare_task_priority); */
  _list_item *list_item, *temp;
  _task_item *task_item;

  list_item = active_task_list_header->next->next;
  while (list_item != active_task_list_header->prev) {
    task_item = &list_item->data.task_item;
    if (task_item->option.count == KILL_COUNT) {
      temp = list_item->next;
      Kill_item(active_task_list_header, (_list_item *)task_item->root);
      pfree(task_item->root);
      list_item = temp;
      continue;
    };
    (*task_item->fp)(&task_item->option);
    if (task_item->option.count >= ONETIME_COUNT) {
      task_item->option.count--;
      Task_Add_Ex(task_item);
    };
    if (task_item->option.count <= INFINITY_COUNT) {
      task_item->option.count--;
      int_wrap(&task_item->option.count);
      Task_Add_Ex(task_item);
    };
    temp = list_item->next;
    Kill_item(active_task_list_header, (_list_item *)task_item->root);
    pfree(task_item->root);
    list_item = temp;
  };
  Swap_task_list_header(&active_task_list_header, &expired_task_list_header);
}

static void Task_Add_Ex(_task_item *src_task_item)
{
  _list_item *list_item;
  list_item = (_list_item *)pmalloc(sizeof(_list_item));
  Add_item_last(expired_task_list_header, list_item);
  _task_item *task_item = &list_item->data.task_item;

  *task_item = *src_task_item;
  task_item->root = list_item;
}

static void Swap_task_list_header(_list_header **argA, _list_header **argB)
{
  _list_header *temp;
  temp = *argA;
  *argA = *argB;
  *argB = temp;
}

